﻿using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Documents;
using System.Windows.Media;
using AgileObjects.AgileMapper;
using BDSync.Domains.DBConn;
using BDSync.Domains.DBSnapShot;
using Dapper;
using DB.SchemaSync.Library.Models;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using MSSQL.DBSync.UI.Common.AsyncCmds;
using MSSQL.DBSync.UI.Common.Messages;
using MSSQL.DBSync.UI.Components.MainWindow;
using MSSQL.DBSync.UI.Components.MakeComparsion.vos;
using MSSQL.DBSync.UI.Components.ManageConn;
using MSSQL.DBSync.UI.Components.VOS;
using Serilog;
using Index = DB.SchemaSync.Library.Models.Index;
using Table = DB.SchemaSync.Library.Models.Table;

namespace MSSQL.DBSync.UI.Components.MakeComparsion
{
    public class MakeComparsionVM : ViewModelBase , IMakeComparsionVM
    {
        private IDBCompareServices cmpSvc;
        private IDBConnService mConnSvc;
        private IMsgWindow msgWindow;

        public MakeComparsionVM()
        {
            initDesignData();
        }

        public MakeComparsionVM(IDBCompareServices svc,IDBConnService connSvc,IMsgWindow msgwindow)
        {
            cmpSvc = svc;
            mConnSvc = connSvc;
            msgWindow = msgwindow;

            initDesignData();

            Messenger.Default.Register<String>(this, MessageTopics.APP_Conn_Update, GetAllHandler);
            GetAllHandler();
        }

        /// <summary>
        /// 初始化设计数据
        /// </summary>
        private void initDesignData()
        {
            CompareObjects = new ObservableCollection<CompareResVO>();
            //CompareObjects.Add(new CompareResVO { IsSelect = true, ChangeType = "ADD", Name = "Color1", TypeName = "column", Desc = "desc1..." });
            //CompareObjects.Add(new CompareResVO { IsSelect = false, ChangeType = "ADD", Name = "Color1", TypeName = "column", Desc = "desc1..." });

            Conns = new ObservableCollection<ConnObjVO>();
            //Conns.Add(new ConnObjVO { Host = "10.9.0.6", DB = "eComm", PWD = "Abc@123456!!", User = "sa" });
            //Conns.Add(new ConnObjVO { Host = "10.9.0.6", DB = "eCommTest", PWD = "Abc@123456!!", User = "sa" });
        }

        private void GetAllHandler(string msg = null)
        {
            var res = mConnSvc.FindAll();
            var objs = Mapper.Map(res).ToANew<List<ConnObjVO>>();
            Conns.Clear();
            objs.ForEach(x => Conns.Add(x));
        }

        private string mSourceDbFile;
        /// <summary>
        /// 导出保存路径
        /// </summary>
        public string SourceDbFile
        {
            get
            {
                return mSourceDbFile;
            }
            set
            {
                Set(ref mSourceDbFile, value);
               
            }
        }

        private RelayCommand mOpenSourceDbFile;
        /// <summary>
        /// 打开目录
        /// </summary>
        public RelayCommand OpenSourceDbFile
        {
            get
            {
                //非空判断
                if (mOpenSourceDbFile != null) { return mOpenSourceDbFile; }
                mOpenSourceDbFile = new RelayCommand(() => {
                        Messenger.Default.Send<Action<string>>(FetchSourceDbFile, MessageTopics.APP_OpenJSONFile);
                    }
                );
                return mOpenSourceDbFile;
            }
            set { mOpenSourceDbFile = value; }
        }

        public void FetchSourceDbFile(string path)
        {
            SourceDbFile = path;
            //todo ... resolve this src db schema 
        }

        private string mSqlFile;
        /// <summary>
        /// 导出保存路径
        /// </summary>
        public string SqlFile
        {
            get
            {
                return mSqlFile;
            }
            set
            {
                Set(ref mSqlFile, value);

            }
        }

        private AsyncCommand mSaveSqlFile;
        /// <summary>
        /// 打开目录
        /// </summary>
        public AsyncCommand SaveSqlFile
        {
            get
            {
                //非空判断
                if (mSaveSqlFile != null) { return mSaveSqlFile; }
                    mSaveSqlFile = new AsyncCommand(async () => {
                        Messenger.Default.Send<Action<string>>(WriteSqlFile, MessageTopics.APP_SaveSqlFile);
                    }
                );
                return mSaveSqlFile;
            }
            set { mSaveSqlFile = value; }
        }

        private void WriteSqlFile(string path)
        {
            //todo ... 
            SqlFile = path;

            try
            {
                if (string.IsNullOrWhiteSpace(SqlFile))
                {
                    throw new ArgumentException("必须指定导出文件");
                }

                if (!CompareObjects.Any())
                {
                    throw new ApplicationException("未检查到任何差异");
                }

                //全部导出 或者 选择导出
                if (CompareObjects.All(x => x.IsSelect) || CompareObjects.All(x => !x.IsSelect))
                {
                    //全选全不选都是全部导出
                    cmpSvc.ExportSqlFile(SqlFile);
                }
                else
                {
                    cmpSvc.ExportSqlFileForSelection(SqlFile);
                }
            }
            catch (Exception e)
            {
                Log.Logger.Error(e, "导出失败");
                Messenger.Default.Send("导出失败", MessageTopics.APP_ShowError);
            }
        }

        private int mDBConnCheckState = 0;
        /// <summary>
        /// 0 未连通
        /// 1 已连通
        /// 2 连接错误
        /// </summary>
        public int DBConnCheckState
        {
            get
            {
                return mDBConnCheckState;
            }
            set
            {
                Set(ref mDBConnCheckState, value);
                //通知按钮命令状态变化
            }
        }


        private string mConnstr;
        /// <summary>
        /// 数据连接字符串
        /// </summary>
        public string Connstr
        {
            get
            {
                return mConnstr;
            }
            set
            {
                Set(ref mConnstr, value);
                DBConnCheckState = 0;
            }
        }

        private string mHost;
        /// <summary>
        /// 主机
        /// </summary>
        public string Host
        {
            get
            {
                return mHost;
            }
            set
            {
                Set(ref mHost, value);
                DBConnCheckState = 0;
            }
        }

        private string mUser;
        /// <summary>
        /// 用户
        /// </summary>
        public string User
        {
            get
            {
                return mUser;
            }
            set
            {
                Set(ref mUser, value);
                DBConnCheckState = 0;
            }
        }

        private string mPwd;
        /// <summary>
        /// 密码
        /// </summary>
        public string Pwd
        {
            get
            {
                return mPwd;
            }
            set
            {
                Set(ref mPwd, value);
                DBConnCheckState = 0;
            }
        }


        private string mDataBase;
        /// <summary>
        /// 数据库
        /// </summary>
        public string DataBase
        {
            get
            {
                return mDataBase;
            }
            set
            {
                Set(ref mDataBase, value);
                DBConnCheckState = 0;
            }
        }

        private AsyncCommand mCheckConn;
        /// <summary>
        /// 初始化设置首页内容
        /// </summary>
        public AsyncCommand CheckConn
        {
            get
            {
                //非空判断
                if (mCheckConn != null) { return mCheckConn; }
                mCheckConn = new AsyncCommand(CheckConnHandler);
                return mCheckConn;
            }
            set { mCheckConn = value; }
        }

        private async Task CheckConnHandler()
        {
            //var sampleMessageDialog = new SampleMessageDialog {Message = { Text = "" }};
            //await DialogHost.Show(sampleMessageDialog,"");
            var str = $"Data Source={Host};Initial Catalog={DataBase};User id={User};Password={Pwd}";

            //if (string.IsNullOrWhiteSpace(Connstr))
            //{
            //    Messenger.Default.Send("必须输入有效主机，用户名，密码", MessageTopics.APP_ShowError);
            //    return;
            //}

            Connstr = str;
            cmpSvc.DbTarConnStr = Connstr;
            if (cmpSvc.CheckConn())
            {
                DBConnCheckState = 1;
                Messenger.Default.Send("连接成功!", MessageTopics.APP_ShowMessage);
            }
            else
            {
                DBConnCheckState = 2;
                Messenger.Default.Send("连接失败!", MessageTopics.APP_ShowError);
            }
        }


        private AsyncCommand mCmpareDb;
        /// <summary>
        /// 初始化设置首页内容
        /// </summary>
        public AsyncCommand CmpareDb
        {
            get
            {
                if (mCmpareDb != null) { return mCmpareDb; }
                mCmpareDb = new AsyncCommand(ScanDBHandler);
                return mCmpareDb;
            }
            set { mCmpareDb = value; }
        }

        /// <summary>
        /// 扫描数据处理程序
        /// </summary>
        /// <returns></returns>
        private async Task ScanDBHandler()
        {
            try
            {
                if (DBConnCheckState != 1)
                {
                    Messenger.Default.Send("数据库必须连通", MessageTopics.APP_ShowError);
                    return;
                }

                if (string.IsNullOrWhiteSpace(SourceDbFile))
                {
                    Messenger.Default.Send("必须选择源库文件", MessageTopics.APP_ShowError);
                    return;
                }

                var res = await cmpSvc.ExceCompare(SourceDbFile);

                CompareObjects.Clear();

                if (!res.Create.Any() && !res.Alter.Any() && !res.Drop.Any())
                {
                    Messenger.Default.Send("没有检测到任何变化", MessageTopics.APP_ShowMessage);
                    return;
                }

                if (res.Create != null)
                {
                    foreach (var cre in res.Create)
                    {
                        var cpItem = new CompareResVO();
                        
                        cpItem.Type = cre.GetType();
                        cpItem.TypeName = cre.GetType().Name;
                        
                        BuildCompareVo(cre, cpItem);
                        cpItem.ChangeType = "Add";

                        cpItem.RefObject = cre;
                        CompareObjects.Add(cpItem);
                    }
                }

                if (res.Alter != null)
                {
                    foreach (var alt in res.Alter)
                    {
                        var cpItem = new CompareResVO();
                        
                        cpItem.Type = alt.Destination.GetType();
                        cpItem.TypeName = alt.Destination.GetType().Name;
                        

                        BuildCompareVo(alt.Destination, cpItem);
                        cpItem.ChangeType = "Modify";

                        cpItem.RefObject = alt.Destination;
                        CompareObjects.Add(cpItem);
                    }
                }

                if (res.Drop != null)
                {
                    foreach(var drp in res.Drop)
                    {
                        var cpItem = new CompareResVO();
                        
                        cpItem.Type = drp.GetType();
                        cpItem.TypeName = drp.GetType().Name;
                        

                        BuildCompareVo(drp, cpItem);
                        cpItem.ChangeType = "Delete";

                        cpItem.RefObject = drp;
                        CompareObjects.Add(cpItem);
                    }
                }

            }
            catch (Exception e)
            {
                Messenger.Default.Send("数据库必须连通", MessageTopics.APP_ShowError);
                Log.Logger.Error(e,"数据比较执行报错");
            }
        }


        /// <summary>
        /// 构造比较对象信息
        /// </summary>
        /// <param name="cre"></param>
        /// <param name="cpItem"></param>
        private static void BuildCompareVo(DbObject cre, CompareResVO cpItem)
        {

            if (cre is Table)
            {
                var tb = (Table)cre;
                cpItem.Name = tb.Name;
                cpItem.Desc = $"Table:{tb.Schema}.{tb.Name}";
            }
            else if (cre is Column)
            {
                var col = (Column) cre;
                cpItem.Name = col.Name;
                cpItem.Desc = $"column:{col.Table.Name}.{col.Name}";
            }
            else if (cre is Index)
            {
                var idx = (Index) cre;
                cpItem.Name = idx.Name;
                cpItem.Desc = $"index:{idx.Table.Name}.{idx.Name}";
            }
            else if (cre is Trigger)
            {
                var tri = (Trigger) cre;
                cpItem.Name = tri.Name;
                cpItem.Desc = $"index:{tri.Table.Name}.{tri.Name}";
            }
            else if (cre is Module)
            {
                var md = (Module) cre;
                cpItem.TypeName = (md.Type == ModuleType.Procedure ? "Procedure" : "Funciton");
                cpItem.Name = md.Name;
                cpItem.Desc = $"{cpItem.TypeName}:{cpItem.Name}";
            }
            else if (cre is View)
            {
                var md = (View) cre;
                cpItem.Name = md.Name;
                cpItem.Desc = $"view:{cpItem.Name}";
            }
            else
            {
                cpItem.Name = cre.InternalId.ToString();
                cpItem.Desc = $"Other:{cpItem.Name}";
            }
        }


        public ObservableCollection<CompareResVO> CompareObjects { get; set; }



        private bool mIsSelectAll ;
        /// <summary>
        /// 是否连接所有
        /// </summary>
        public bool IsSelectAll
        {
            get
            {
                return mIsSelectAll;
            }
            set
            {
                Set(ref mIsSelectAll, value);

                //重置明细
                foreach (var cpvo in CompareObjects)
                {
                    cpvo.IsSelect = value;
                }
            }
        }

        #region showmodel demo 

        //private RelayCommand mShowModel;
        ///// <summary>
        ///// 打开目录
        ///// </summary>
        //public RelayCommand ShowModel
        //{
        //    get
        //    {
        //        //非空判断
        //        if (mOpenSourceDbFile != null) { return mOpenSourceDbFile; }

        //        mOpenSourceDbFile = new RelayCommand(async () => {
        //            var view = new SampleMessageDialog { };
        //            //show the dialog
        //            var result = await DialogHost.Show(view, "RootDialog", ClosingEventHandler);
        //        });

        //        return mOpenSourceDbFile;
        //    }
        //    set { mOpenSourceDbFile = value; }
        //}

        //private void ClosingEventHandler(object sender, DialogClosingEventArgs eventArgs)
        //    => Console.WriteLine("You can intercept the closing event, and cancel here.");

        #endregion


        private RelayCommand mExecSql;
        /// <summary>
        /// 打开目录
        /// </summary>
        public RelayCommand ExecSql
        {
            get
            {
                //非空判断
                if (mExecSql != null) { return mExecSql; }
                mExecSql = new RelayCommand(ExecSqlHadnler);
                return mExecSql;
            }
            set { mExecSql = value; }
        }


        private void ExecSqlHadnler()
        {
            try
            {
                if (!CompareObjects.Any())
                {
                    throw new ApplicationException("未检查到任何差异");
                }

                var act = new Action<int>((code) =>
                {
                    var res = string.Empty;
                    if (code == 1)
                    {
                        //全部导出 或者 选择导出
                        if (CompareObjects.All(x => x.IsSelect) || CompareObjects.All(x => !x.IsSelect))
                        {
                            //全选全不选都是全部导出
                            res = cmpSvc.ExecSql();
                        }
                        else
                        {
                            
                            res = cmpSvc.ExecSqlForSelection();
                        }

                        if (string.IsNullOrWhiteSpace(res))
                        {
                            Messenger.Default.Send("执行成功", MessageTopics.APP_ShowMessage);
                        }
                        else
                        {
                            msgWindow.Show(res);
                        }


                        //清理比较对象
                        CompareObjects.Clear();
                    }
                });

                var par = (mgs : "操作会使用数据库永久变更，请确认已备份，再继续!", cb : act);
                Messenger.Default.Send(par, MessageTopics.APP_Confirm);
              
            }
            catch (Exception e)
            {
                
                Log.Logger.Error(e, "执行失败");
                Messenger.Default.Send($"执行失败:{e.Message}", MessageTopics.APP_ShowError);
            }
        }

        public ObservableCollection<ConnObjVO> Conns { get; set; }

        private ConnObjVO mCurConn;
        /// <summary>
        /// 数据库
        /// </summary>
        public ConnObjVO CurConn
        {
            get
            {
                return mCurConn;
            }
            set
            {
                Set(ref mCurConn, value);
                if (mCurConn != null)
                {
                    DataBase = mCurConn.DB;
                    User = mCurConn.User;
                    Pwd = mCurConn.PWD;
                    Host = mCurConn.Host;
                }
            }
        }

        private RelayCommand mGotoConnEdit;
        /// <summary>
        /// 打开目录
        /// </summary>
        public RelayCommand GotoConnEdit
        {
            get
            {
                //非空判断
                if (mGotoConnEdit != null) { return mGotoConnEdit; }
                mGotoConnEdit = new RelayCommand(() =>
                {
                    Messenger.Default.Send(typeof(IManageConnView), MessageTopics.APP_GotoPage);
                });
                return mGotoConnEdit;
            }
            set { mGotoConnEdit = value; }
        }


    }
}